package tcln.sors.client.core.mvc;

import java.awt.Dialog;
import java.awt.Window;

import javax.swing.JComponent;
import javax.swing.JFrame;

import tcln.commons.assertion.Assert;

/**
 * Default implementation for a {@link View} which contains basic and most common information for a view.
 * 
 * @param <M>
 *            Model data type.
 * @param <D>
 *            Display component type.
 * @author Truong Chau Lien Ngoc (lienngoc@gmail.com)
 */
public class DefaultView<M extends ModelData<?>, D extends Window> implements View<M> {
    protected View<?> parentView;
    protected M modelData;
    protected D displayComponent;

    /**
     * constructs this view by default.
     */
    public DefaultView() {
        displayComponent = initDisplayComponent();
        displayComponent.setName("displayComponent");
        initialize();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void setParentView(View<?> parent) {
        this.parentView = parent;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public D getDisplayComponent() {
        return displayComponent;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void setModel(M model) {
        this.modelData = model;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public M getModel() {
        return modelData;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void show(boolean center) {
        Assert.STATE.notNull(displayComponent, "Display component is missing");
        onShowing();
        displayComponent.pack();
        if (center) {
            displayComponent.setLocationRelativeTo(parentView == null ? null : parentView.getDisplayComponent());
        }
        displayComponent.setVisible(true);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void hide() {
        onHiding();
        displayComponent.setVisible(false);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void unload() {
        onUnloading();
        hide();
        displayComponent.dispose();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void showModal(boolean center) {
        if (displayComponent instanceof Dialog) {
            ((Dialog) displayComponent).setModal(true);
            show(center);
        } else {
            Assert.STATE.fail("Display component is not a {0}", Dialog.class);
        }
    }

    /**
     * Fires just before this view is shown. This should be the place where model should be attached to the view
     * components.
     */
    protected void onShowing() {
        // template
    }

    /**
     * Fires just before this view is hidden.
     */
    protected void onHiding() {
        // template
    }

    /**
     * Fires just before this view is unloaded.
     */
    protected void onUnloading() {
        // template
    }

    /**
     * Initializes the display component. This implementation creates a new {@link JFrame} component. Subclasses may
     * override this method to add other components.
     */
    protected D initDisplayComponent() {
        return (D) new JFrame();
    }

    /**
     * Initializes this view itself.
     * <p>
     * <b>Note</b>: This method is invoked after {@link #initDisplayComponent()} finishes.
     */
    protected void initialize() {
        // template
    }

    /**
     * Standardizes a given component for current application.
     * 
     * @param component
     * @return Given component after changing according to the standard of current application.
     */
    protected JComponent standardize(JComponent component) {
        // template
        return component;
    }
}
